/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.babeuf.form.fields.input 
{
	import flash.text.TextField;
	import net.babeuf.form.messages.Messages;
	/**
	 * Numeric field for credit card validation
	 * You can define wich cards are allowed
	 * @author Damien Pegoraro
	 */
	public class CreditCardField extends NumericField 
	{
		protected var _allowMasterCard : Boolean = true ; 
		protected var _allowVisa : Boolean = true  ;
		protected var _allowAmericanExpress : Boolean = true ; 
		protected var _allowDinersClub : Boolean = true ; 
		protected var _allowDiscover : Boolean = true ; 
		protected var _allowEnRoute : Boolean = true ; 
		protected var _allowJCB : Boolean = true ; 
		
		protected var _type : String ; 
		
		
		protected static const MASTER : String = "master" ; 
		protected static const VISA : String = "visa" ; 
		protected static const AMEX : String = "amex" ; 
		protected static const DINER : String = "diner" ; 
		protected static const DISCOVER : String = "discover" ; 
		protected static const ENROUTE : String = "enroute" ; 
		protected static const JCB1 : String = "jcb1" ; 
		protected static const JCB2 : String = "jcb2" ; 
		
		
		
		public function CreditCardField( textField : TextField ) 
		{
			super( textField, 13, 16 ) ; 
		}
		
				
		override public function validate():Boolean 
		{	
			if ( !super.validate() ) return false ; 		
			if ( optional && getValue() == "" ) return true ; 			
			resolveType() ;				
			checkCardValidity() ; 	
			setSize(13, 16) ; 
			if ( _error != "" ) {_updateSensors(false) ;  return false ; }			
			return true ; 
		}
		
		private function resolveType():void 
		{
			if ( getValue().indexOf( "51") == 0 ||  getValue().indexOf( "52") == 0 ||  getValue().indexOf( "53") == 0 ||  getValue().indexOf( "54") == 0 ||  getValue().indexOf( "55") == 0)
			{
				_type = MASTER ; 
				setSize(16, 16) ; 
				if ( !_allowMasterCard ) _error = _invalidError ; 
			}
			else 
			if ( getValue().indexOf("4") == 0 ) 
			{
				_type = VISA ; 
				setSize(13, 16) ;
				if ( !_allowVisa ) _error = _invalidError ; 
			}
			else 
			if ( getValue().indexOf("34") == 0 || getValue().indexOf("37") == 0) 
			{
				_type = AMEX ; 
				setSize(15, 15) ; 
				if ( !_allowAmericanExpress ) _error = _invalidError ; 
			}
			else 
			if ( getValue().indexOf("38") == 0 || getValue().indexOf("36") == 0 || getValue().indexOf("300") == 0 || getValue().indexOf("301") == 0 || getValue().indexOf("302") == 0 || getValue().indexOf("303") == 0 || getValue().indexOf("304") == 0 || getValue().indexOf("305") == 0) 
			{
				_type = DINER ; 
				setSize(14, 14) ; 
				if ( !_allowDinersClub ) _error = _invalidError ; 
			}
			else 
			if ( getValue().indexOf("6011") == 0 ) 
			{
				_type = DISCOVER ; 
				setSize(16, 16) ; 
				if ( !_allowDiscover ) _error = _invalidError ;
			}
			else 
			if ( getValue().indexOf("2014") == 0 || getValue().indexOf("2149") == 0) 
			{
				_type = ENROUTE ; 
				setSize(15, 15) ; 
				if ( !_allowEnRoute ) _error = _invalidError ; 
			}
			else 
			if ( getValue().indexOf("3") == 0 ) 
			{
				_type = JCB1 ; 
				setSize(16, 16) ; 
				if ( !_allowJCB ) _error = _invalidError ; 
			}
			else 
			if ( getValue().indexOf("2131") == 0 || getValue().indexOf("1800") == 0 ) 
			{
				_type = JCB2 ; 
				setSize(15, 15) ; 
				if ( !_allowJCB ) _error = _invalidError ; 
			}
			else _type = "" ;			
		}
		
		protected function checkCardValidity():void 
		{
			if ( _type == "" ) _error = _invalidError ; 
			else  if ( _type != ENROUTE ) 			
			{
				checkLUHN() ; 
			}
			
		}
		
		private function checkLUHN():void 
		{
			var input : String = getValue() ; 			
			var total : int = 0 ;
			var length : Number = input.length;			
			var mul : Number = 1;
			
			for ( var i : uint = 0 ; i < length ; ++i )
			{
				var char : String = input.substr( length - 1 - i, 1 ) ;
				var prod : Number = parseInt(char, 10) * mul ; 				
				total += prod >= 10 ? (prod % 10) + 1 : prod ; 				
				mul = mul == 1 ? mul +1 : mul - 1 ; 
			}			
			if ( (total % 10) != 0 )
			{
				_error = _invalidError ; 			
			}
		}
				
		
		public function setInvalidCardNumberError( code:String ):void 
		{
			_invalidError = code ; 
		}	
		
		//GETTERS AND SETTERS FOR ALLOWED TYPES
		
	
		public function get allowMasterCard():Boolean 
		{
			return _allowMasterCard;
		}
		
		public function set allowMasterCard(value:Boolean):void 
		{
			_allowMasterCard = value;
		}
		
		public function get allowVisa():Boolean 
		{
			return _allowVisa;
		}
		
		public function set allowVisa(value:Boolean):void 
		{
			_allowVisa = value;
		}
		
		public function get allowAmericanExpress():Boolean 
		{
			return _allowAmericanExpress;
		}
		
		public function set allowAmericanExpress(value:Boolean):void 
		{
			_allowAmericanExpress = value;
		}
		
		public function get allowDinersClub():Boolean 
		{
			return _allowDinersClub;
		}
		
		public function set allowDinersClub(value:Boolean):void 
		{
			_allowDinersClub = value;
		}
		
		public function get allowDiscover():Boolean 
		{
			return _allowDiscover;
		}
		
		public function set allowDiscover(value:Boolean):void 
		{
			_allowDiscover = value;
		}
		
		public function get allowEnRoute():Boolean 
		{
			return _allowEnRoute;
		}
		
		public function set allowEnRoute(value:Boolean):void 
		{
			_allowEnRoute = value;
		}
		
		public function get allowJCB():Boolean 
		{
			return _allowJCB;
		}
		
		public function set allowJCB(value:Boolean):void 
		{
			_allowJCB = value;
		}
		
	}

}